package com.base.project

import android.content.Context
import com.blankj.utilcode.util.AppUtils
import com.blankj.utilcode.util.DeviceUtils
import com.blankj.utilcode.util.LanguageUtils
import com.blankj.utilcode.util.LogUtils
import com.google.gson.JsonSyntaxException
import com.jeremyliao.liveeventbus.LiveEventBus
import com.orange.common.BuildConfig
import com.orange.common.helper.UserHelper
import com.orange.common.ktx.encrtpyMD5
import com.orange.common.net.ktx.code
import com.orange.common.net.ktx.rxHttpGlobalCatch
import com.orange.common.net.ktx.rxHttpThrowableFormatMsg
import com.orange.common.util.TimeUtils
import kotlinx.coroutines.TimeoutCancellationException
import okhttp3.OkHttpClient
import rxhttp.RxHttpPlugins
import rxhttp.wrapper.cache.CacheMode
import rxhttp.wrapper.converter.GsonConverter
import rxhttp.wrapper.cookie.CookieStore
import rxhttp.wrapper.entity.KeyValuePair
import rxhttp.wrapper.exception.HttpStatusCodeException
import rxhttp.wrapper.exception.ParseException
import rxhttp.wrapper.param.FormParam
import rxhttp.wrapper.param.Method
import rxhttp.wrapper.param.NoBodyParam
import rxhttp.wrapper.param.Param
import rxhttp.wrapper.ssl.HttpsUtils
import java.io.File
import java.net.ConnectException
import java.net.SocketTimeoutException
import java.net.UnknownHostException
import java.util.concurrent.TimeUnit
import java.util.concurrent.TimeoutException
import kotlin.random.Random


/**
 * Created by Orange on 2022/11/14 19:45.
 * 参考
 * https://github.com/liujingxing/rxhttp/blob/master/app/src/main/java/com/example/httpsender/RxHttpManager.java
 */
object RxHttpManager {

    const val APPID = "android_v1"

    const val KEY = """!2TkSL6Y80${'$'}hp8Dw#jWhocN3RwiHjM@Hs!"""

    fun init(context: Context) {
        //异常处理
        initGlobalCatch()
        // ssl
        val sslParams = HttpsUtils.getSslSocketFactory()
        // cookie 目录
        val file = File(context.externalCacheDir, "RxHttpCookie")
        // 设置缓存目录，非必须
        val cacheFile = File(context.externalCacheDir, "RxHttpCache")

        val builder = OkHttpClient.Builder()
            .cookieJar(CookieStore(file))
            .connectTimeout(30, TimeUnit.SECONDS)
            .readTimeout(30, TimeUnit.SECONDS)
            .writeTimeout(30, TimeUnit.SECONDS)
        if (BuildConfig.DEBUG){
            //这里会信任所有证书导致可使用Fiddler抓包，正式版不开启
            builder.sslSocketFactory(sslParams.sSLSocketFactory, sslParams.trustManager) //添加信任证书
                .hostnameVerifier { _, _ -> true } //忽略host验证
        }
            //.addNetworkInterceptor(logInterceptor)

        //RxHttp初始化，自定义OkHttpClient对象，非必须
        RxHttpPlugins.init(builder.build())
            .setDebug(BuildConfig.DEBUG, true, 2)  //调试模式/分段打印/json数据缩进空间
            .setConverter(GsonConverter.create())
            .setCache( //设置最大缓存为10M，缓存有效时长为60秒 全局缓存模式，这里为，先请求网络，失败后，再读取缓存
                cacheFile,
                10 * 1024 * 1024,
                CacheMode.ONLY_NETWORK,
                60 * 1000
            )
            .setExcludeCacheKeys(//设置一些key，不参与cacheKey的组拼
                "apiSign",
                "nonceStr",
                "timeStamp"
            )
            //.setResultDecoder(s -> s)                  //设置数据解密/解码器，非必须
            .setOnParamAssembly { p ->
                // 添加签名
                apiSign(p)
                // 公共头部参数
                p.addHeader("qr-client", "android")
                    .addHeader("qr-ver", AppUtils.getAppVersionName())                              // 版本名称
                    .addHeader("qr-ver-code", AppUtils.getAppVersionCode().toString())              // 版本号
                    .addHeader("qr-device", DeviceUtils.getAndroidID().uppercase())                 // android id
                    .addHeader("qr-model", DeviceUtils.getModel())                                  // 设备型号
                    .addHeader("qr-country", LanguageUtils.getSystemLanguage().country)             // 系统语言 国家
                    .addHeader("qr-locale", LanguageUtils.getSystemLanguage().language)             // 系统语言 语言
                    .addHeader("qr-timezone", TimeUtils.getTimeZoneOffset().toString())             // 时区偏移值
                    .addHeader("qr-tz", TimeUtils.getTimeZone())                                    // 系统时区
                    .addHeader("qr-app-lang", "0")                                                  // app 语言代号
                    .addHeader("qr-adid", Constants.adId)                                        // 谷歌广告id
                    .addHeader("qr-token", UserHelper.user.token)                                   // token
            }
    }

    private fun initGlobalCatch() {
        rxHttpGlobalCatch = { t: Throwable ->
            t.run {
                LogUtils.e("rxhttp 请求异常:$message")
                //处理全局异常
                when (code) {
                    //账号已在别处登录
                    2003 -> {
                        LiveEventBus.get<Any>(Constants.Events.LOGIN_ERROR).post(null)
                        true
                    }

                    else -> {
                        // 没有处理的异常
                        false
                    }
                }
            }
        }

        rxHttpThrowableFormatMsg = { t: Throwable ->
            when (t) {
                //网络异常
                is UnknownHostException -> {
                    TH.getString("app_network_error") //当前无网络，请检查你的网络设置
                }
                //okhttp全局设置超时 || rxjava中的timeout方法超时 || 协程超时
                is SocketTimeoutException, is TimeoutException, is TimeoutCancellationException -> {
                    TH.getString("app_network_error") //连接超时,请稍后再试
                }

                is ConnectException -> {
                    TH.getString("app_network_error") //网络不给力，请稍候重试！
                }
                //请求失败异常
                is HttpStatusCodeException -> {
                    //"Http状态码异常"
                    t.localizedMessage
                }
                //请求成功，但Json语法异常,导致解析失败
                is JsonSyntaxException -> {
                    TH.getString("app_net_hin4") //数据解析失败,请检查数据是否正确
                }
                //ParseException异常表明请求成功，但是数据不正确
                is ParseException -> {
                    //msg为空，显示code
                    t.message ?: t.errorCode
                }

                else -> {
                    TH.getString("app_network_error")//请求失败，请稍后再试
                }
            }
        }
    }

    private fun apiSign(p: Param<*>) {

        val method: Method = p.method

        var params: MutableList<KeyValuePair> = ArrayList()

        if (method.isGet) {
            //Get请求
            if (p is NoBodyParam) {
                p.queryParam?.let { params.addAll(it) }
            }
        } else if (method.isPost) {
            //Post请求
            if (p is FormParam) {
                p.bodyParam?.let { params.addAll(it) }
            }
        }

        val timeStamp = System.currentTimeMillis() / 1000
        val random1 = Random.nextInt(0, 100)
        val random2 = Random.nextInt(0, 100)
        var nonceStr = "$random1$timeStamp$random2".encrtpyMD5()

        if (nonceStr.length > 15) {
            nonceStr = nonceStr.substring(0, 12)
        }

        params.add(KeyValuePair("appId", APPID))
        params.add(KeyValuePair("timeStamp", timeStamp))
        params.add(KeyValuePair("nonceStr", nonceStr))

        //按key的字母序排序用&拼接字符串
        params.sortWith { o1, o2 ->
            o1.key.compareTo(o2.key)
        }
        val sb = StringBuilder()
        for (param in params) {
            sb.append(param.key).append("=").append(param.value).append("&")
        }

        val sign = sb.append("key=${KEY}").toString()

        LogUtils.d("apiSign: sign = $sign")

        p.add("appId", APPID)
            .add("timeStamp", timeStamp)
            .add("nonceStr", nonceStr)
            .add("apiSign", sign.encrtpyMD5().uppercase())
    }
}